﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;

namespace iChip.Hostpots.Commons
{
    public class UserAgentParser
    {
        protected static Hashtable HasBrowser = new Hashtable();
        protected static Hashtable HasOperator = new Hashtable();
        public static void Init()
        {
            for (int i = 0; i < Browsers.Length / 2; i++)
            {
                string key = Browsers[i, 0];
                string value = Browsers[i, 1];
                if (HasBrowser == null || !HasBrowser.ContainsKey(key))
                {
                    HasBrowser.Add(key, value);
                }
            }
            for (int i = 0; i < OperatingSystems.Length / 2; i++)
            {
                string key = OperatingSystems[i, 0];
                string value = OperatingSystems[i, 1];
                if (HasOperator == null || !HasOperator.ContainsKey(key))
                {
                    HasOperator.Add(key, value);
                }
            }
            for (int i = 0; i < OperationSystemsIdToShortName.Length / 2; i++)
            {
                string key = OperationSystemsIdToShortName[i, 0];
                string value = OperationSystemsIdToShortName[i, 1];
                if (HasOperatorShortName == null || !HasOperatorShortName.ContainsKey(key))
                {
                    HasOperatorShortName.Add(key, value);
                }
            }
        }
        static protected string BrowserIdToName = string.Empty;
        static protected string BrowserIdToShortName = string.Empty;
        static protected string OperatingSystemsIdToName = string.Empty;
        static protected string OperatingSystemsIdToShortName = string.Empty;
        static private bool init = false;
        protected static Hashtable HasOperatorShortName = new Hashtable();
        static public BrowserInfo GetBrowser(string userAgent)
        {

            Init();
            BrowserInfo brInfo = new BrowserInfo();
            if (userAgent.ToUpper().Contains("MSIE"))
            {
                //compatible; MSIE 6.0; Windows
                Regex reg = new Regex("compatible; MSIE ([0-9]+)([.0-9]+); Windows", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
                brInfo.Name = "Internet Explorer";
                brInfo.ID = "IE";
                brInfo.ShortName = "Internet Explorer";
                brInfo.MajorNumber = reg.Match(userAgent).Groups[1].Value;
                brInfo.MinorNumber = reg.Match(userAgent).Groups[2].Value.Trim('.');
                brInfo.version = brInfo.MajorNumber + "." + brInfo.MinorNumber.Split('.')[0];
            }
            if (userAgent.Contains("BlackBerry"))
            {
                brInfo.ID = "BB";
                brInfo.Name = "BlackBerry";

            }
            if (userAgent.Contains("RIM Tablet OS"))
            {
                brInfo.ID = "BP";
                brInfo.Name = "RIM Tablet OS";
            }
            userAgent = Regex.Replace(userAgent, @"BlackBerry\d+/", "BlackBerry/", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            userAgent = Regex.Replace(userAgent, @"Mozilla\/[0-9.]+", "", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);

            userAgent = Regex.Replace(userAgent, @"Mozilla\/[0-9.]+ \([^)]+\)", "", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            userAgent = Regex.Replace(userAgent, @"(AppleWebKit)[\/\sa-z(]*([0-9]+)([\.0-9a-z]+)", "", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Regex regBrowser = new Regex(@"([a-zA-Z0-9]+)\/([0-9a-z]+)([.0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            MatchCollection maths = regBrowser.Matches(userAgent);

            foreach (Match math in maths)
            {
                if (HasBrowser.ContainsKey(math.Groups[1].Value.ToLower()))
                {
                    brInfo.Name = math.Groups[1].Value;
                    brInfo.ID = HasBrowser[math.Groups[1].Value.ToLower()].ToString();
                    brInfo.MajorNumber = math.Groups[2].Value;
                    brInfo.ShortName = math.Groups[1].Value;
                    brInfo.MinorNumber = math.Groups[3].Value.Trim('.');
                    brInfo.version = brInfo.MajorNumber + "." + brInfo.MinorNumber.Split('.')[0][0];
                    break;
                }
            }
            //Version/12.00
            Regex regVersion = new Regex(@"Version/([0-9a-z]+)([.0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match matchVersion = regVersion.Match(userAgent);
            if (matchVersion.Success)
            {
                brInfo.MajorNumber = matchVersion.Groups[1].Value;
                brInfo.MinorNumber = matchVersion.Groups[2].Value.Trim('.');
                brInfo.version = brInfo.MajorNumber + "." + brInfo.MinorNumber.Split('.')[0][0];
            }
            return brInfo;

        }

        static public string GetOperatingSystemById(string systemId)
        {
            return HasOperatorShortName[systemId].ToString();
        }


        static public OperatorInfo GetOperatingSystem(string userAgent)
        {
            Init();
            OperatorInfo info = new OperatorInfo();
            foreach (string key in HasOperator.Keys)
            {
                if (userAgent.Contains(key))
                {
                    info.ID = HasOperator[key].ToString();
                    info.Name = key;
                    info.ShortName = GetOperatingSystemById(HasOperator[key].ToString());
                    break;
                }
            }
            return info;
        }

        protected static string[,] OperationSystemsIdToShortName =
        {
            {"PS3", "PS3"},
            {
                "PSP", "PSP"
            },
            {
                "MAC", "MAC"
            },
            {
                "WII", "Wii"
            },
            {
                "NDS", "DS"
            },
            {
                "DSI", "DSi"
            },
            {
                "WI8", "Win 8"
            },
            {
                "WI7", "Win 7"
            },
            {
                "WVI", "Win Vista"
            },
            {
                "WS3", "Win S2003"
            },
            {
                "WXP", "Win XP"
            },
            {
                "W98", "Win 98"
            },
            {
                "W2K", "Win 2000"
            },
            {
                "WNT", "Win NT"
            },
            {
                "WME", "Win Me"
            },
            {
                "W95", "Win 95"
            },
            {
                "WPH", "WinPhone"
            },
            {
                "WMO", "WinMo"
            },
            {
                "WCE", "Win CE"
            },
            {
                "WOS", "webOS"
            },
            {
                "UNK", "Unknown"
            },
            {
                "IPH", "iPhone"
            },
            {
                "IPD", "iPod"
            },
            {
                "IPA", "iPad"
            },
            {
                "IOS", "iOS"
            },
            {
                "BLB", "BlackBerry"
            },
            {
                "QNX", "RIM Tablet OS"
            },
            {
                "LIN", "Linux"
            },
            {
                "AND", "Android"
            }
        };

        static protected string[,] OperatingSystems = {
        {"Android"				, "AND"},{
		"Maemo"					, "MAE"},{
		"Linux"					, "LIN"},{

		// workaround for vendors who changed the WinPhone 7 user agent
		"WP7"					, "WPH"},{

		"CYGWIN_MT-6.2"			, "WI8"},{
		"Windows NT 6.2"		, "WI8"},{
		"Windows 8"				, "WI8"},{
		"CYGWIN_NT-6.1"			, "WI7"},{
		"Windows NT 6.1"		, "WI7"},{
		"Windows 7"				, "WI7"},{
		"CYGWIN_NT-6.0"			, "WVI"},{
		"Windows NT 6.0"		, "WVI"},{
		"Windows Vista"			, "WVI"},{
		"CYGWIN_NT-5.2"			, "WS3"},{
		"Windows NT 5.2"		, "WS3"},{
		"Windows Server 2003 / XP x64" , "WS3"},{
		"CYGWIN_NT-5.1"			, "WXP"},{
		"Windows NT 5.1"		, "WXP"},{
		"Windows XP"			, "WXP"},{
		"CYGWIN_NT-5.0"			, "W2K"},{
		"Windows NT 5.0"		, "W2K"},{
		"Windows 2000"			, "W2K"},{
		"CYGWIN_NT-4.0"			, "WNT"},{
		"Windows NT 4.0"		, "WNT"},{
		"WinNT"					, "WNT"},{
		"Windows NT"			, "WNT"},{
		"CYGWIN_ME-4.90"		, "WME"},{
		"Win 9x 4.90"			, "WME"},{
		"Windows ME"			, "WME"},{
		"CYGWIN_98-4.10"		, "W98"},{
		"Win98"					, "W98"},{
		"Windows 98"			, "W98"},{
		"CYGWIN_95-4.0"			, "W95"},{
		"Win32"					, "W95"},{
		"Win95"					, "W95"},{		
		"Windows 95"			, "W95"},{

		// Windows Phone OS 7 and above
		"Windows Phone OS"		, "WPH"},{

		// Windows Mobile 6.x and some later versions of Windows Mobile 5
		"IEMobile"			, "WMO"},{ // fallback
		"Windows Mobile"		, "WMO"},{

		// Windows CE, Pocket PC, and Windows Mobile 5 are indistinguishable without vendor/device specific detection
		"Windows CE"			, "WCE"},{

		"iPod"					, "IPD"},{
		"iPad"					, "IPA"},{
		"iPhone"				, "IPH"},{
		"iOS"					, "IOS"},{
		"Darwin"				, "MAC"},{
		"Macintosh"				, "MAC"},{
		"Power Macintosh"		, "MAC"},{
		"Mac_PowerPC"			, "MAC"},{ 
		"Mac PPC"				, "MAC"},{
		"PPC"					, "MAC"},{
		"Mac PowerPC"			, "MAC"},{
		"Mac OS"				, "MAC"},{

		"webOS"					, "WOS"},{
		"Palm webOS"			, "WOS"},{
		"PalmOS"				, "POS"},{
		"Palm OS"				, "POS"},{

		"BlackBerry"			, "BLB"},{
		"RIM Tablet OS"			, "QNX"},{
		"QNX"					, "QNX"},{

		"SymbOS"				, "SYM"},{
		"Symbian OS"			, "SYM"},{
		"SymbianOS"				, "SYM"},{

		"bada"					, "SBA"},{

		"SunOS"					, "SOS"},{
		"AIX"					, "AIX"},{
		"HP-UX"					, "HPX"},{
		"OpenVMS"				, "VMS"},{

		"FreeBSD"				, "BSD"},{
		"NetBSD"				, "NBS"},{
		"OpenBSD"				, "OBS"},{
		"DragonFly"				, "DFB"},{
		"Syllable"				, "SYL"},{

		"Nintendo Wii"			, "WII"},{
		"Nitro"					, "NDS"},{
		"Nintendo DS "			, "NDS"},{
		"Nintendo DSi"			, "DSI"},{
		"PlayStation Portable"	, "PSP"},{
		"PlayStation 3"			, "PS3"},{

		"IRIX"					, "IRI"},{
		"OSF1"					, "T64"},{
		"OS/2"					, "OS2"},{
		"BEOS"					, "BEO"},{
		"Amiga"					, "AMI"},{
		"AmigaOS"				, "AMI"}
        };

        static protected string[,] Browsers = {
            {
        "abrowse"						, "AB"},{
        "amaya"							, "AM"},{
        "amigavoyager"					, "AV"},{
        "amiga-aweb"					, "AW"},{
        "arora"							, "AR"},{
        "beonex"						, "BE"},{

        // BlackBerry smartphones and tablets
        "blackberry"					, "BB"},{ // BlackBerry 6 and PlayBook adopted webkit
        "playbook"						, "BP"},{

        "browsex"						, "BX"},{

        // Camino (and earlier incarnation)
        "chimera"						, "CA"},{
        "camino"						, "CA"},{

        "cheshire"						, "CS"},{

        // Chrome, Chromium, and ChromePlus
        "crmo"							, "CH"},{
        "chrome"						, "CH"},{

        "cometbird"						, "CO"},{
        "dillo"							, "DI"},{
        "elinks"						, "EL"},{
        "epiphany"						, "EP"},{
        "fennec"						, "FE"},{

        // Dolfin (or Dolphin)
        "dolfin"						, "DF"},{

        // Firefox (in its many incarnations and rebranded versions)
        "phoenix"						, "PX"},{
        "mozilla firebird"				, "FB"},{
        "firebird"						, "FB"},{
        "bonecho"						, "FF"},{
        "minefield"						, "FF"},{
        "namoroka"						, "FF"},{
        "shiretoko"						, "FF"},{
        "granparadiso"					, "FF"},{
        "iceweasel"						, "FF"},{
        "icecat"						, "FF"},{
        "firefox"						, "FF"},{

        "flock"							, "FL"},{
        "fluid"							, "FD"},{
        "galeon"						, "GA"},{
        "google earth"					, "GE"},{
        "hana"							, "HA"},{
        "hotjava"						, "HJ"},{
        "ibrowse"						, "IB"},{
        "icab"							, "IC"},{

        // IE (including shells: Acoo, AOL, Avant, Crazy Browser, Green Browser, KKMAN, Maxathon)
        "msie"							, "IE"},{
        "microsoft internet explorer"	, "IE"},{
        "internet explorer"				, "IE"},{
        "iron"							, "IR"},{
        "kapiko"						, "KP"},{
        "kazehakase"					, "KZ"},{
        "k-meleon"						, "KM"},{
        "konqueror"						, "KO"},{
        "links"							, "LI"},{
        "lynx"							, "LX"},{
        "midori"						, "MI"},{
        //"trident"						, "IE"},{
        // SeaMonkey (formerly Mozilla Suite) (and rebranded versions)
        "mozilla"						, "MO"},{
        "gnuzilla"						, "SM"},{
        "iceape"						, "SM"},{
        "seamonkey"						, "SM"},{
        "trident"	          			, "TD"},{
        // NCSA Mosaic (and incarnations)
        "mosaic"						, "MC"},{
        "ncsa mosaic"					, "MC"},{

        // Netscape Navigator
        "navigator"						, "NS"},{
        "netscape6"						, "NS"},{
        "netscape"						, "NS"},{

        "omniweb"						, "OW"},{

        // Opera
        "nitro) opera"					, "OP"},{
        "opera"							, "OP"},{
    
        // Safari
        "safari"						, "SF"},{
        "applewebkit"					, "SF"},{

        "titanium"						, "TI"},{

        "webos"							, "WO"},{
        "webpro"						, "WP"}
    };
    }

    public class OperatorInfo
    {
        public string ID { get; set; }
        public string Name { get; set; }
        public string ShortName { get; set; }
    }
    public class BrowserInfo
    {
        public string ID { get; set; }
        public string Name { get; set; }
        public string ShortName { get; set; }
        public string MajorNumber { get; set; }
        public string MinorNumber { get; set; }
        public string version { get; set; }
    }
}